How to use PDO with MySQL database

php pdo mysql

(Originally posted on my Portuguese blog at rberaldo.com.br)

Starting from PHP 5.5, the MySQL library in PHP, with functions like mysql_connect and mysql_query, is considered outdated. I talked about this in this post. The most recommended alternative is to use the PDO extension.

However, many programmers still don’t know how to use PDO. I will show in this post how simple it is to use this class.

It’s very important to use PDO for two main reasons:

  1. Your code becomes cleaner and more modern.
  2. It’s easy to migrate to another Database Management System (DBMS) if necessary in the future.

But if you are reading this post, you probably already know that.

What Is PDO

PDO stands for PHP Data Objects. It is a class for managing database connections. Yes, databases. This means you can use PDO to connect to many DBMS, including MySQL, PostgreSQL, SQLite, MS SQL Server, Oracle, and others.

PDO Is Object-Oriented

PDO is a class. It follows the Object-Oriented Programming (OOP) paradigm. If you’re not familiar with OOP, I recommend studying it a bit before using PDO.

You don’t need to go too deep. Just understand what classes, objects, and methods are. Learn how to instantiate objects and call their methods. That’s sufficient to work with PDO.

Table Used for This Tutorial

I’ve created a table called “programmers” with ID, name, and website for each of them. I used the following SQL to create the table and its data:

CREATE TABLE programmers(
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    name VARCHAR(80) NOT NULL,
    website VARCHAR(120) DEFAULT NULL,
    PRIMARY KEY(id)
);
 
INSERT INTO programmers(name, website) VALUES
('Beraldo', 'https://beraldo.dev'),
('John', NULL),
('Mary', 'http://mariaprogramadora.com.br'),
('Joseph', 'http://joseprogramador.com.br'),
('Linus Torvalds', 'http://kernel.org'),
('Mark Zuckerberg', 'http://facebook.com'),
('Steve Wozniak', 'http://apple.com');

Connecting to MySQL Using PDO

Let’s define constants to store the connection data:

define('MYSQL_HOST', 'localhost');
define('MYSQL_USER', 'root');
define('MYSQL_PASSWORD', '');
define('MYSQL_DB_NAME', 'pdo_tutorial');

The connection is established by the constructor of the PDO class. That is, you just need to pass the connection data as parameters when you instantiate the PDO class, like this:

$PDO = new PDO('mysql:host='. MYSQL_HOST . ';dbname=' . MYSQL_DB_NAME, MYSQL_USER, MYSQL_PASSWORD);

This works. However, if the connection fails, an exception will be thrown, and the execution will be stopped.

To avoid this, we should put this code in a try…catch block and handle the PDOException exception. The code will look like this:

try {
    $PDO = new PDO('mysql:host=' . MYSQL_HOST . ';dbname=' . MYSQL_DB_NAME, MYSQL_USER, MYSQL_PASSWORD);
} catch (PDOException $e) {
    echo 'Erro ao conectar com o MySQL: ' . $e->getMessage();
}

Setting UTF-8 Encoding

To set UTF-8 encoding (or another encoding if you are not already using UTF-8), execute the following query right after opening the connection:

phpCopy code

$PDO->exec("set names utf8");

Executing SELECT with PDO

With the instance of the PDO class in the variable $PDO, you can perform a simple SELECT like this:

$sql = "SELECT * FROM programmers";
$result = $PDO->query($sql);
$rows = $result->fetchAll();
 
print_r($rows);

The query method of the PDO class executes a query and, in the case of SELECT, returns an object of type PDOStatement. This object has the fetchAll method, which is similar to the mysql_fetch_array function, returning an array with all the records. We use the print_r function to display this array. The output will be like this:

Array
(
    [0] => Array
        (
            [id] => 1
            [0] => 1
            [nome] => Beraldo
            [1] => Beraldo
            [site] => https://beraldo.dev
            [2] => https://beraldo.dev
        )

    [1] => Array
        (
            [id] => 2
            [0] => 2
            [nome] => John
            [1] => John
            [site] => 
            [2] => 
        )

    [2] => Array
        (
            [id] => 3
            [0] => 3
            [nome] => Mary
            [1] => Mary
            [site] => http://mariaprogramadora.com.br
            [2] => http://mariaprogramadora.com.br
        )

    [3] => Array
        (
            [id] => 4
            [0] => 4
            [nome] => Joseph
            [1] => Joseph
            [site] => http://joseprogramador.com.br
            [2] => http://joseprogramador.com.br
        )

    [4] => Array
        (
            [id] => 5
            [0] => 5
            [nome] => Linus Torvalds
            [1] => Linus Torvalds
            [site] => http://kernel.org
            [2] => http://kernel.org
        )

    [5] => Array
        (
            [id] => 6
            [0] => 6
            [nome] => Mark Zuckerberg
            [1] => Mark Zuckerberg
            [site] => http://facebook.com
            [2] => http://facebook.com
        )

    [6] => Array
        (
            [id] => 7
            [0] => 7
            [nome] => Steve Wozniak
            [1] => Steve Wozniak
            [site] => http://apple.com
            [2] => http://apple.com
        )
)

For each record, you’ll see duplicated values. They appear in two indices: one is the field number in the table, and the other is the field name. This consumes double the memory. That’s why it’s recommended to return only the record with the field names.

To do that, pass the PDO::FETCH_ASSOC parameter to the fetchAll method. It will work similarly to the mysql_fetch_assoc function, returning only the associative array with field names. Change the line calling the fetchAll method like this:

$rows = $result->fetchAll(PDO::FETCH_ASSOC);

The displayed array will look like this:

Array
(
    [0] => Array
        (
            [id] => 1
            [nome] => Beraldo
            [site] => https://beraldo.dev
        )

    [1] => Array
        (
            [id] => 2
            [nome] => John
            [site] => 
        )

    [2] => Array
        (
            [id] => 3
            [nome] => Mary
            [site] => http://mariaprogramadora.com.br
        )

    [3] => Array
        (
            [id] => 4
            [nome] => Joseph
            [site] => http://joseprogramador.com.br
        )

    [4] => Array
        (
            [id] => 5
            [nome] => Linus Torvalds
            [site] => http://kernel.org
        )

    [5] => Array
        (
            [id] => 6
            [nome] => Mark Zuckerberg
            [site] => http://facebook.com
        )

    [6] => Array
        (
            [id] => 7
            [nome] => Steve Wozniak
            [site] => http://apple.com
        )
)

Filtering Queries

Usually, our SELECT queries have a WHERE clause to filter results. It’s straightforward to do using PDO.

Let’s consider the following situation: we will request the user to define a string to use as a filter in the SELECT. The filtering will be done on the “site” field of our table.

$search = $_GET['search'];
$sql = "SELECT * FROM programmers WHERE website LIKE '%" . $search . "%'";
$result = $PDO->query($sql);
$rows = $result->fetchAll(PDO::FETCH_ASSOC);

Suppose the user entered the word “programmer.” Therefore, $_GET['search'] will be the string “programmer.”

The $rows array will look like this:

Array
(
    [0] => Array
        (
            [id] => 3
            [nome] => Maria
            [site] => http://mariaprogramadora.com.br
        )

    [1] => Array
        (
            [id] => 4
            [nome] => Joseph
            [site] => http://joseprogramador.com.br
        )
)

But there is a more efficient and secure way to pass parameters for queries: using Prepared Statements.

What Are Prepared Statements and How to Use Them

Prepared Statements are useful for executing the same query multiple times with different parameters efficiently. However, they also serve another purpose: native query filtering to prevent SQL Injection, adding extra security to your system.

In this type of query, parameters are not sent directly in the query. They are sent in a separate “package” to the MySQL server. The server then associates the SQL string with the parameters.

In other words, we won’t directly put the $search variable in the query.

With Prepared Statements, your code will look like this:

$search = $_GET['search'];
$search = '%' . $search . '%';
$sql = "SELECT * FROM programmers WHERE website LIKE :search";
$stmt = $PDO->prepare($sql);
$stmt->bindParam(':search', $search);
$result = $stmt->execute();

Now, our query contains only the value “:search” in the WHERE clause. This is how the query will be sent to MySQL. With the bindParam method, we specify that we want to send the value of $search, which will replace :search.

Since we are using LIKE, we had to manually add the percentage signs (%) on the second line. If we were searching for exact strings (with the = operator), we wouldn’t need that.

The $rows array will be the same as in the previous code.

Using Prepared Statements makes your code much safer. You can also specify the data type by passing the third parameter to bindParam. The possible values are:

  • PDO::PARAM_BOOL
  • PDO::PARAM_NULL
  • PDO::PARAM_INT
  • PDO::PARAM_STR (this is the default value)
  • PDO::PARAM_LOB

These parameters tell MySQL how to treat each value. For example, strings need to be enclosed in single quotes, but integers don’t. That’s why it’s important to pass these parameters when the value is not a string.

INSERT, DELETE, and UPDATE Using PDO

These three commands will be handled similarly. Here’s how to perform an INSERT:

$name = 'Bill Gates';
$website = 'http://microsoft.com';
$sql = "INSERT INTO programmers(name, website) VALUES(:name, :website)";
$stmt = $PDO->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':website', $website);

$result = $stmt->execute();

if (!$result) {
    var_dump($stmt->errorInfo());
    exit;
}

echo $stmt->rowCount() . " lines inserted";

Let’s assume that $name and $website come from a form. Therefore, we need to filter these values using Prepared Statements.

For the UPDATE operation, let’s assume we want to change the “website” value to “http://windows.com.br” for the name “Bill Gates.” The code is as follows:

$name = 'Bill Gates';
$website = 'http://ruindows.com.br';
$sql = "UPDATE programmers set website = :website WHERE name = :name";
$stmt = $PDO->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':website', $website);

$result = $stmt->execute();

if (!$result) {
    var_dump($stmt->errorInfo());
    exit;
}

echo $stmt->rowCount() . " lines updated";

The DELETE operation will look like this:

$name = 'Bill Gates';
$sql = "DELETE FROM programmers WHERE name = :name";
$stmt = $PDO->prepare($sql);
$stmt->bindParam(':name', $name);

$result = $stmt->execute();

if (!$result) {
    var_dump($stmt->errorInfo());
    exit;
}

echo $stmt->rowCount() . " lines removed";

Conclusion

I hope you found this tutorial useful. There are many other features of the PDO extension. You can read about them all in the Official Extension Documentation.

Related posts

33 Thoughts to “How to use PDO with MySQL database”

  1. Estou meio enferrujado no PHP e preciso lembrar para dar aulas rsrs. Muito legal essas novas funções do PHP 7.

    1. Olá.
      O PDO existe, na verdade, desde o PHP 5.1.
      O PHP 7 removeu a extensão mysql, recomendando usar mysqli ou PDO (ambos já existiam há anos).
      Se quiser conhecer as novidades do PHP 7, veja este meu curso gratuito: http://cursophp7.ultimatephp.com.br

  2. Antonio Junior

    Obrigado Beraldo por compartilhar essa informação.

    1. Olá, Antonio.

      Que bom que o artigo foi útil pra você 🙂

      Abraço

  3. Comecei a estudar PHP há poucas semanas, daí nas pesquisas que fiz eu vi que o PDO é o mais recomendado e estou começando a estudá-lo. Muito obrigado por compartilhar esse conhecimento.

    1. PDO é, realmente, a melhor opção. Bons estudos! 🙂

  4. Bryan Didur

    Obrigado pelo Ótimo artigo! Ajudou muito!

    Mas eu tenho uma dúvida, vi em alguns lugares que pode-se usar o Prepared Statements usando a ‘?’ na $sql, mas passando o valor da ‘?’ no método execute() da PDO dentro de um array.

    Exemplo:

    $sql = “SELECT * FROM tabela WHERE id = ? “;

    e depois na execução ficaria assim:

    $query->execute( array(1) ); // Funciona normalmente

    Qual é a diferença dessa forma de informar o valor, para as formas que passam valores pelos ” bind’s ” ? Além da não verificação do tipo de dado.

    Desde já agradeço pelos excelentes artigos que posta aqui. Estão me ajudando muito em meus estudos sobre o PHP OO.

    Muito Obrigado Novamente!

    1. Eu não gosto muito dessa forma, principalmente quando há muitos parâmetros. Aí fica assim:

      ->prepare(‘SELECT … WHERE para1 = ?, param2 = ?, param3 =? …’)
      ->execute(‘param1’, ‘param2’, ‘param3’…);

      Acho que fica pouco legível. Mas pra quando há poucos parâmetros, não tem problema.

      1. Renan

        No “prepare” não tem como fugir kkk ou então, joga todo o select pra uma variável $sqlSelect e cria um array de parâmetros executando somente o array. Por exemplo:

        $stmt = $pdo->prepare($sqlSelect);
        $p[“:descricao”] = $descricao;
        $p[“:estoque”] = $estoque;
        $p[“:preco”] = $preco;
        $p[“:validade”] = $validade;
        if ($stmt->execute($p))
        …..

  5. Helder Tosta

    Beraldo, qual a diferença entre bindParam e bindValue?

  6. Adriano Alves

    Muito bom seu artigo bem claro! Eu fiz uns códigos para tá passando um valor de uma página que resgata os dados e atribui a uma variável em outra página pelo método Post vou ver se com as suas explicações funciona agora pois ela envia o valor mais não realiza a deleção nem a edição e não acho erro caso não funcione postarei aki para vc me ajudar! Já agradeço pelo ótimo Post seu Beraldo

  7. Obrigado por compartilhar o artigo. Vejo muitas dúvidas sobre o PDO, e achei seu artigo muito completo. Parabéns!

  8. Clovis Junior

    COMO CRIA BANCO DE DADOS COM PDO ???????????????? #$@

    1. Você pode usar o método query() ou execute() para executar o comando CREATE DATABASE. Porém, em geral, as aplicações não criam o banco.

  9. Anderson Aluizio

    Muito bom, venho acompanhando seu site.
    Obrigado pelo artigo!

  10. Rafael Silveira

    A tempos já trabalhava com a conexão PDO, porém agora..passei para o php 7 e simplismente não puxa nada do banco de dados. Uso o try/catch e nenhum erro aparece.

    Algo parecido com algum de vocês?
    Sabem resolver?

  11. Aguinaldo Antonio Hurbik

    Boa Tarde! Podem me ajudar nesse erro?

    Notice: Undefined index: digitenome in C:xampphtdocstestecadastrandonome.php on line 15
    array(3) { [0]=> string(5) “23000” [1]=> int(1048) [2]=> string(34) “Column ‘digitenome’ cannot be null” }

      1. Aguinaldo Antonio Hurbik

        não estou conseguindo pegar o conteúdo do formulário html para trabalhar com ele no php

        1. Você deve estar errando o “name” do campo HTML. Compare o valor dele com o que está usando no índice do array $_POST

          1. Aguinaldo Antonio Hurbik

            Era isso mesmo, muito obrigado.

  12. Nilson Silva

    Excelente artigo, muito útil. Parabéns!

  13. Muito bom bem explicado parabéns

  14. Ênio Lemos

    Para mim o fatchall não funcionou para usar o LIKE da forma que foi posta no site. Tive que executar assim:

    $stmt = $PDO->prepare( ‘SELECT * FROM programadores WHERE site LIKE ?’ );
    $stmt->execute(array($search));
    $rows = $stmt->fetchAll( PDO::FETCH_ASSOC );

    print_r($rows);

  15. Maicom Ferreira

    Valeu! Eu estou querendo aprender a usar o PDO, mas, estava com um problema, que toda vez que eu tentava fazer igual ao exemplo ou parecido, em outros lugares, dava erro(ou não funcionava igual), mas aqui funcionou. Obrigado pelo excelente tutorial.

  16. Clovis Junior

    Ruindows kkk

Leave a Comment